<?php

/**
 * Request class
 *
 *
 * @package    lib
 * @subpackage lib_request
 * @author     Juan Carlos Jarquin (zetta)
 * @author     Zend_Framework
 * @author     $LastChangedBy$
 * @version    1.1, SVN: $Id$
 */
class Request
{
  
  /**
   * Scheme for http
   *
   */
  const SCHEME_HTTP = 'http';
  
  /**
   * Scheme for https
   *
   */
  const SCHEME_HTTPS = 'https';
  
  /**
   * @var Request
   */
  private static $instance = null;
  
  /**
   * Allowed parameter sources
   * @var array
   */
  protected $paramSources = array('_GET', '_POST');
  
  /**
   * REQUEST_URI
   * @var string;
   */
  protected $requestUri;
  
  /**
   * Base URL of request
   * @var string
   */
  protected $baseUrl = null;
  
  /**
   * Base path of request
   * @var string
   */
  protected $basePath = null;
  
  /**
   * PATH_INFO
   * @var string
   */
  protected $pathInfo = '';
  
  /**
   * Instance parameters
   * @var array
   */
  protected $params = array();
  
  /**
   * Raw request body
   * @var string|false
   */
  protected $rawBody;
  
  /**
   * Alias keys for request parameters
   * @var array
   */
  protected $aliases = array();
  
  /**
   * Controller
   * @var string
   */
  protected $controller;

  /**
   * Controller key for retrieving controller from params
   * @var string
   */
  protected $controllerKey = 'controller';

  /**
   * Action
   * @var string
   */
  protected $action;

  /**
   * Action key for retrieving action from params
   * @var string
   */
  protected $actionKey = 'action';
  
  /**
   * Constructor Class
   * @return Request
   */
  private function Request()
  {
    
    $this->setRequestUri();
  
  }
  
  /**
   * Get the class instance
   * @return Request
   */
  public function getInstance()
  {
    if (self::$instance == null)
    {
      self::$instance = new Request();
    }
    return self::$instance;
  }
  

  /**
   * Return the value of the given HTTP header. Pass the header name as the
   * plain, HTTP-specified header name. Ex.: Ask for 'Accept' to get the
   * Accept header, 'Accept-Encoding' to get the Accept-Encoding header.
   *
   * @param string $header HTTP header name
   * @return string|false HTTP header value, or false if not found
   * @throws RequestException
   */
  public function getHeader($header)
  {
    if (empty($header))
    {
      throw new RequestException('An HTTP header name is required');
    }
    
    // Try to get it from the $_SERVER array first
    $temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
    if (! empty($_SERVER [$temp]))
    {
      return $_SERVER [$temp];
    }
    
    // This seems to be the only way to get the Authorization header on
    // Apache
    if (function_exists('apache_request_headers'))
    {
      $headers = apache_request_headers();
      if (! empty($headers [$header]))
      {
        return $headers [$header];
      }
    }
    
    return false;
  }
  
  /**
   * Get the HTTP host.
   *
   * "Host" ":" host [ ":" port ] ; Section 3.2.2
   * Note the HTTP Host header is not the same as the URI host.
   * It includes the port while the URI host doesn't.
   *
   * @return string
   */
  public function getHttpHost()
  {
    $host = $this->getServer('HTTP_HOST');
    if (! empty($host))
    {
      return $host;
    }
    
    $scheme = $this->getScheme();
    $name = $this->getServer('SERVER_NAME');
    $port = $this->getServer('SERVER_PORT');
    
    if (($scheme == self::SCHEME_HTTP && $port == 80) || ($scheme == self::SCHEME_HTTPS && $port == 443))
    {
      return $name;
    }
    else
    {
      return $name . ':' . $port;
    }
  }
  
  /**
   * Get the request URI scheme
   *
   * @return string
   */
  public function getScheme()
  {
    return ($this->getServer('HTTPS') == 'on') ? self::SCHEME_HTTPS : self::SCHEME_HTTP;
  }
  
  /**
   * Get the client's IP addres
   *
   * @return string
   */
  public function getClientIp($checkProxy = true)
  {
    if ($checkProxy && $this->getServer('HTTP_CLIENT_IP') != null)
    {
      $ip = $this->getServer('HTTP_CLIENT_IP');
    }
    else if ($checkProxy && $this->getServer('HTTP_X_FORWARDED_FOR') != null)
    {
      $ip = $this->getServer('HTTP_X_FORWARDED_FOR');
    }
    else
    {
      $ip = $this->getServer('REMOTE_ADDR');
    }
    
    return $ip;
  }
  
  /**
   * Access values contained in the superglobals as public members
   * Order of precedence: 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV
   *
   * @see http://msdn.microsoft.com/en-us/library/system.web.httprequest.item.aspx
   * @param string $key
   * @return mixed
   */
  public function __get($key)
  {
    switch (true)
    {
      case isset($this->params [$key]) :
        return $this->params [$key];
      case isset($_GET [$key]) :
        return $_GET [$key];
      case isset($_POST [$key]) :
        return $_POST [$key];
      case isset($_COOKIE [$key]) :
        return $_COOKIE [$key];
      case ($key == 'REQUEST_URI') :
        return $this->getRequestUri();
      case ($key == 'PATH_INFO') :
        return $this->getPathInfo();
      case isset($_SERVER [$key]) :
        return $_SERVER [$key];
      case isset($_ENV [$key]) :
        return $_ENV [$key];
      default :
        return null;
    }
  }
  
  /**
   * Alias to __get
   *
   * @param string $key
   * @return mixed
   */
  public function get($key)
  {
    return $this->__get($key);
  }
  
  /**
   * Set values
   *
   * In order to follow {@link __get()}, which operates on a number of
   * superglobals, setting values through overloading is not allowed and will
   * raise an exception. Use setParam() instead.
   *
   * @param string $key
   * @param mixed $value
   * @return void
   * @throws RequestException
   */
  public function __set($key, $value)
  {
    throw new RequestException("Setting values in superglobals not allowed; please use setParam({$key},{$value})");
  }
  
  /**
   * Alias to __set()
   *
   * @param string $key
   * @param mixed $value
   * @return void
   */
  public function set($key, $value)
  {
    return $this->__set($key, $value);
  }
  
  /**
   * Check to see if a property is set
   *
   * @param string $key
   * @return boolean
   */
  public function __isset($key)
  {
    switch (true)
    {
      case isset($this->params [$key]) :
        return true;
      case isset($_GET [$key]) :
        return true;
      case isset($_POST [$key]) :
        return true;
      case isset($_COOKIE [$key]) :
        return true;
      case isset($_SERVER [$key]) :
        return true;
      case isset($_ENV [$key]) :
        return true;
      default :
        return false;
    }
  }
  
  /**
   * Alias to __isset()
   *
   * @param string $key
   * @return boolean
   */
  public function has($key)
  {
    return $this->__isset($key);
  }
  
  /**
   * Set GET values
   *
   * @param  string|array $spec
   * @param  null|mixed $value
   * @return RequestException
   */
  public function setQuery($spec, $value = null)
  {
    if ((null === $value) && ! is_array($spec))
    {
      throw new RequestException('Invalid value passed to setQuery(); must be either array of values or key/value pair');
    }
    if ((null === $value) && is_array($spec))
    {
      foreach ($spec as $key => $value)
      {
        $this->setQuery($key, $value);
      }
      return $this;
    }
    $_GET [(string) $spec] = $value;
    return $this;
  }
  
  /**
   * Retrieve a member of the $_GET superglobal
   *
   * If no $key is passed, returns the entire $_GET array.
   *
   * @todo How to retrieve from nested arrays
   * @param string $key
   * @param mixed $default Default value to use if key not found
   * @return mixed Returns null if key does not exist
   */
  public function getQuery($key = null, $default = null)
  {
    if (null === $key)
    {
      return $_GET;
    }
    
    return (isset($_GET [$key])) ? $_GET [$key] : $default;
  }
  
  /**
   * Set POST values
   *
   * @param  string|array $spec
   * @param  null|mixed $value
   * @return Request
   */
  public function setPost($spec, $value = null)
  {
    if ((null === $value) && ! is_array($spec))
    {
      throw new RequestException('Invalid value passed to setPost(); must be either array of values or key/value pair');
    }
    if ((null === $value) && is_array($spec))
    {
      foreach ($spec as $key => $value)
      {
        $this->setPost($key, $value);
      }
      return $this;
    }
    $_POST [(string) $spec] = $value;
    return $this;
  }
  
  /**
   * Retrieve a member of the $_POST superglobal
   *
   * If no $key is passed, returns the entire $_POST array.
   *
   * @todo How to retrieve from nested arrays
   * @param string $key
   * @param mixed $default Default value to use if key not found
   * @return mixed Returns null if key does not exist
   */
  public function getPost($key = null, $default = null)
  {
    if (null === $key)
    {
      return $_POST;
    }
    return (isset($_POST [$key])) ? $_POST [$key] : $default;
  }
  
  /**
   * Retrieve a member of the $_COOKIE superglobal
   *
   * If no $key is passed, returns the entire $_COOKIE array.
   *
   * @todo How to retrieve from nested arrays
   * @param string $key
   * @param mixed $default Default value to use if key not found
   * @return mixed Returns null if key does not exist
   */
  public function getCookie($key = null, $default = null)
  {
    if (null === $key)
    {
      return $_COOKIE;
    }
    return (isset($_COOKIE [$key])) ? $_COOKIE [$key] : $default;
  }
  
  /**
   * Retrieve a member of the $_SERVER superglobal
   *
   * If no $key is passed, returns the entire $_SERVER array.
   *
   * @param string $key
   * @param mixed $default Default value to use if key not found
   * @return mixed Returns null if key does not exist
   */
  public function getServer($key = null, $default = null)
  {
    if (null === $key)
    {
      return $_SERVER;
    }
    return (isset($_SERVER [$key])) ? $_SERVER [$key] : $default;
  }
  
  /**
   * Retrieve a member of the $_ENV superglobal
   *
   * If no $key is passed, returns the entire $_ENV array.
   *
   * @param string $key
   * @param mixed $default Default value to use if key not found
   * @return mixed Returns null if key does not exist
   */
  public function getEnv($key = null, $default = null)
  {
    if (null === $key)
    {
      return $_ENV;
    }
    return (isset($_ENV [$key])) ? $_ENV [$key] : $default;
  }
  
  /**
   * Set the REQUEST_URI on which the instance operates
   *
   * If no request URI is passed, uses the value in $_SERVER['REQUEST_URI'],
   * $_SERVER['HTTP_X_REWRITE_URL'], or $_SERVER['ORIG_PATH_INFO'] + $_SERVER['QUERY_STRING'].
   *
   * @param string $requestUri
   * @return Request
   */
  public function setRequestUri($requestUri = null)
  {
    if ($requestUri === null)
    {
      if (isset($_SERVER ['HTTP_X_REWRITE_URL']))
      { // check this first so IIS will catch
        $requestUri = $_SERVER ['HTTP_X_REWRITE_URL'];
      }
      elseif (// IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem)
      isset($_SERVER ['IIS_WasUrlRewritten']) && $_SERVER ['IIS_WasUrlRewritten'] == '1' && isset($_SERVER ['UNENCODED_URL']) && $_SERVER ['UNENCODED_URL'] != '')
      {
        $requestUri = $_SERVER ['UNENCODED_URL'];
      }
      elseif (isset($_SERVER ['REQUEST_URI']))
      {
        $requestUri = $_SERVER ['REQUEST_URI'];
        // Http proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
        $schemeAndHttpHost = $this->getScheme() . '://' . $this->getHttpHost();
        if (strpos($requestUri, $schemeAndHttpHost) === 0)
        {
          $requestUri = substr($requestUri, strlen($schemeAndHttpHost));
        }
      }
      elseif (isset($_SERVER ['ORIG_PATH_INFO']))
      { // IIS 5.0, PHP as CGI
        $requestUri = $_SERVER ['ORIG_PATH_INFO'];
        if (! empty($_SERVER ['QUERY_STRING']))
        {
          $requestUri .= '?' . $_SERVER ['QUERY_STRING'];
        }
      }
      else
      {
        return $this;
      }
    }
    elseif (! is_string($requestUri))
    {
      return $this;
    }
    else
    {
      // Set GET items, if available
      if (false !== ($pos = strpos($requestUri, '?')))
      {
        // Get key => value pairs and set $_GET
        $query = substr($requestUri, $pos + 1);
        parse_str($query, $vars);
        $this->setQuery($vars);
      }
    }
    
    $this->requestUri = $requestUri;
    return $this;
  }
  
  /**
   * Returns the REQUEST_URI taking into account
   * platform differences between Apache and IIS
   *
   * @return string
   */
  public function getRequestUri()
  {
    if (empty($this->requestUri))
    {
      $this->setRequestUri();
    }
    return $this->requestUri;
  }
  
  /**
   * Set the base URL of the request; i.e., the segment leading to the script name
   *
   * E.g.:
   * - /admin
   * - /myapp
   * - /subdir/index.php
   *
   * Do not use the full URI when providing the base. The following are
   * examples of what not to use:
   * - http://example.com/admin (should be just /admin)
   * - http://example.com/subdir/index.php (should be just /subdir/index.php)
   *
   * If no $baseUrl is provided, attempts to determine the base URL from the
   * environment, using SCRIPT_FILENAME, SCRIPT_NAME, PHP_SELF, and
   * ORIG_SCRIPT_NAME in its determination.
   *
   * @param mixed $baseUrl
   * @return Request
   */
  public function setBaseUrl($baseUrl = null)
  {
    if ((null !== $baseUrl) && ! is_string($baseUrl))
    {
      return $this;
    }
    
    if ($baseUrl === null)
    {
      $filename = (isset($_SERVER ['SCRIPT_FILENAME'])) ? basename($_SERVER ['SCRIPT_FILENAME']) : '';
      
      if (isset($_SERVER ['SCRIPT_NAME']) && basename($_SERVER ['SCRIPT_NAME']) === $filename)
      {
        $baseUrl = $_SERVER ['SCRIPT_NAME'];
      }
      elseif (isset($_SERVER ['PHP_SELF']) && basename($_SERVER ['PHP_SELF']) === $filename)
      {
        $baseUrl = $_SERVER ['PHP_SELF'];
      }
      elseif (isset($_SERVER ['ORIG_SCRIPT_NAME']) && basename($_SERVER ['ORIG_SCRIPT_NAME']) === $filename)
      {
        $baseUrl = $_SERVER ['ORIG_SCRIPT_NAME']; // 1and1 shared hosting compatibility
      }
      else
      {
        // Backtrack up the script_filename to find the portion matching
        // php_self
        $path = isset($_SERVER ['PHP_SELF']) ? $_SERVER ['PHP_SELF'] : '';
        $file = isset($_SERVER ['SCRIPT_FILENAME']) ? $_SERVER ['SCRIPT_FILENAME'] : '';
        $segs = explode('/', trim($file, '/'));
        $segs = array_reverse($segs);
        $index = 0;
        $last = count($segs);
        $baseUrl = '';
        do
        {
          $seg = $segs [$index];
          $baseUrl = '/' . $seg . $baseUrl;
          ++ $index;
        } while ( ($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos) );
      }
      
      // Does the baseUrl have anything in common with the request_uri?
      $requestUri = $this->getRequestUri();
      
      if (0 === strpos($requestUri, $baseUrl))
      {
        // full $baseUrl matches
        $this->baseUrl = $baseUrl;
        return $this;
      }
      
      if (0 === strpos($requestUri, dirname($baseUrl)))
      {
        // directory portion of $baseUrl matches
        $this->baseUrl = rtrim(dirname($baseUrl), '/');
        return $this;
      }
      
      $basename = basename($baseUrl);
      if (empty($basename) || ! strpos($requestUri, $basename))
      {
        // no match whatsoever; set it blank
        $this->baseUrl = '';
        return $this;
      }
      
      // If using mod_rewrite or ISAPI_Rewrite strip the script filename
      // out of baseUrl. $pos !== 0 makes sure it is not matching a value
      // from PATH_INFO or QUERY_STRING
      if ((strlen($requestUri) >= strlen($baseUrl)) && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0)))
      {
        $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
      }
    }
    
    $this->baseUrl = rtrim($baseUrl, '/');
    return $this;
  }
  
  /**
   * Everything in REQUEST_URI before PATH_INFO
   * <form action="<?=$baseUrl?>/news/submit" method="POST"/>
   *
   * @return string
   */
  public function getBaseUrl()
  {
    if (null === $this->baseUrl)
    {
      $this->setBaseUrl();
    }
    
    return $this->baseUrl;
  }
  
  /**
   * Set the base path for the URL
   *
   * @param string|null $basePath
   * @return Request
   */
  public function setBasePath($basePath = null)
  {
    if ($basePath === null)
    {
      $filename = (isset($_SERVER ['SCRIPT_FILENAME'])) ? basename($_SERVER ['SCRIPT_FILENAME']) : '';
      
      $baseUrl = $this->getBaseUrl();
      if (empty($baseUrl))
      {
        $this->basePath = '';
        return $this;
      }
      
      if (basename($baseUrl) === $filename)
      {
        $basePath = dirname($baseUrl);
      }
      else
      {
        $basePath = $baseUrl;
      }
    }
    
    if (substr(PHP_OS, 0, 3) === 'WIN')
    {
      $basePath = str_replace('\\', '/', $basePath);
    }
    
    $this->basePath = rtrim($basePath, '/');
    return $this;
  }
  
  /**
   * Everything in REQUEST_URI before PATH_INFO not including the filename
   * <img src="<?=$basePath?>/images/image.png"/>
   *
   * @return string
   */
  public function getBasePath()
  {
    if (null === $this->basePath)
    {
      $this->setBasePath();
    }
    
    return $this->basePath;
  }
  
  /**
   * Set the PATH_INFO string
   *
   * @param string|null $pathInfo
   * @return Request
   */
  public function setPathInfo($pathInfo = null)
  {
    if ($pathInfo === null)
    {
      $baseUrl = $this->getBaseUrl();
      
      if (null === ($requestUri = $this->getRequestUri()))
      {
        return $this;
      }
      
      // Remove the query string from REQUEST_URI
      if (($pos = strpos($requestUri, '?')))
      {
        $requestUri = substr($requestUri, 0, $pos);
      }
      
      if ((null !== $baseUrl) && (false === ($pathInfo = substr($requestUri, strlen($baseUrl)))))
      {
        // If substr() returns false then PATH_INFO is set to an empty string
        $pathInfo = '';
      }
      elseif (null === $baseUrl)
      {
        $pathInfo = $requestUri;
      }
    }
    
    $this->pathInfo = (string) $pathInfo;
    return $this;
  }
  
  /**
   * Returns everything between the BaseUrl and QueryString.
   * This value is calculated instead of reading PATH_INFO
   * directly from $_SERVER due to cross-platform differences.
   *
   * @return string
   */
  public function getPathInfo()
  {
    if (empty($this->pathInfo))
    {
      $this->setPathInfo();
    }
    
    return $this->pathInfo;
  }
  
  /**
   * Set allowed parameter sources
   *
   * Can be empty array, or contain one or more of '_GET' or '_POST'.
   *
   * @param  array $paramSoures
   * @return Zend_Controller_Request_Http
   */
  public function setParamSources(array $paramSources = array())
  {
    $this->paramSources = $paramSources;
    return $this;
  }
  
  /**
   * Get list of allowed parameter sources
   *
   * @return array
   */
  public function getParamSources()
  {
    return $this->paramSources;
  }
  
  /**
   * Set a userland parameter
   *
   * Uses $key to set a userland parameter. If $key is an alias, the actual
   * key will be retrieved and used to set the parameter.
   *
   * @param mixed $key
   * @param mixed $value
   * @return Zend_Controller_Request_Http
   */
  public function setParam($key, $value)
  {
    $key = (null !== ($alias = $this->getAlias($key))) ? $alias : $key;
    $key = (string) $key;
    if ((null === $value) && isset($this->params[$key])) {
      unset($this->params[$key]);
    } elseif (null !== $value) {
      $this->params[$key] = $value;
    }
    return $this;
  }
  
  /**
   * Retrieve a parameter
   *
   * Retrieves a parameter from the instance. Priority is in the order of
   * userland parameters (see {@link setParam()}), $_GET, $_POST. If a
   * parameter matching the $key is not found, null is returned.
   *
   * If the $key is an alias, the actual key aliased will be used.
   *
   * @param mixed $key
   * @param mixed $default Default value to use if key not found
   * @return mixed
   */
  public function getParam($key, $default = null)
  {
    $keyName = (null !== ($alias = $this->getAlias($key))) ? $alias : $key;
    
    $paramSources = $this->getParamSources();
    if (isset($this->params [$keyName]))
    {
      return $this->params [$keyName];
    }
    elseif (in_array('_GET', $paramSources) && (isset($_GET [$keyName])))
    {
      return $_GET [$keyName];
    }
    elseif (in_array('_POST', $paramSources) && (isset($_POST [$keyName])))
    {
      return $_POST [$keyName];
    }
    
    return $default;
  }
  
  /**
   * Retrieve an array of parameters
   *
   * Retrieves a merged array of parameters, with precedence of userland
   * params (see {@link setParam()}), $_GET, $POST (i.e., values in the
   * userland params will take precedence over all others).
   *
   * @return array
   */
  public function getParams()
  {
    $return = $this->params;
    $paramSources = $this->getParamSources();
    if (in_array('_GET', $paramSources) && isset($_GET) && is_array($_GET))
    {
      $return += $_GET;
    }
    if (in_array('_POST', $paramSources) && isset($_POST) && is_array($_POST))
    {
      $return += $_POST;
    }
    return $return;
  }

 
  /**
   * Set parameters
   *
   * Set one or more parameters. Parameters are set as userland parameters,
   * using the keys specified in the array.
   *
   * @param array $params
   * @return Request
   */
  public function setParams(array $params)
  {
    foreach ($params as $key => $value)
    {
      $this->setParam($key, $value);
    }
    return $this;
  }
  
  /**
   * Set a key alias
   *
   * Set an alias used for key lookups. $name specifies the alias, $target
   * specifies the actual key to use.
   *
   * @param string $name
   * @param string $target
   * @return Request
   */
  public function setAlias($name, $target)
  {
    $this->aliases [$name] = $target;
    return $this;
  }
  
  /**
   * Retrieve an alias
   *
   * Retrieve the actual key represented by the alias $name.
   *
   * @param string $name
   * @return string|null Returns null when no alias exists
   */
  public function getAlias($name)
  {
    if (isset($this->aliases [$name]))
    {
      return $this->aliases [$name];
    }
    
    return null;
  }
  
  /**
   * Retrieve the list of all aliases
   *
   * @return array
   */
  public function getAliases()
  {
    return $this->aliases;
  }
  
  /**
   * Return the method by which the request was made
   *
   * @return string
   */
  public function getMethod()
  {
    return $this->getServer('REQUEST_METHOD');
  }
  
  /**
   * Was the request made by POST?
   *
   * @return boolean
   */
  public function isPost()
  {
    if ('POST' == $this->getMethod())
    {
      return true;
    }
    return false;
  }
  
  /**
   * Was the request made by GET?
   *
   * @return boolean
   */
  public function isGet()
  {
    if ('GET' == $this->getMethod())
    {
      return true;
    }
    
    return false;
  }
  
  /**
   * Was the request made by PUT?
   *
   * @return boolean
   */
  public function isPut()
  {
    if ('PUT' == $this->getMethod())
    {
      return true;
    }
    
    return false;
  }
  
  /**
   * Was the request made by DELETE?
   *
   * @return boolean
   */
  public function isDelete()
  {
    if ('DELETE' == $this->getMethod())
    {
      return true;
    }
    
    return false;
  }
  
  /**
   * Was the request made by HEAD?
   *
   * @return boolean
   */
  public function isHead()
  {
    if ('HEAD' == $this->getMethod())
    {
      return true;
    }
    
    return false;
  }
  
  /**
   * Was the request made by OPTIONS?
   *
   * @return boolean
   */
  public function isOptions()
  {
    if ('OPTIONS' == $this->getMethod())
    {
      return true;
    }
    
    return false;
  }
  
  /**
   * Is the request a Javascript XMLHttpRequest?
   *
   * Should work with Prototype/Script.aculo.us, possibly others.
   *
   * @return boolean
   */
  public function isXmlHttpRequest()
  {
    return ($this->getHeader('X_REQUESTED_WITH') == 'XMLHttpRequest');
  }
  
  /**
   * Is this a Flash request?
   *
   * @return bool
   */
  public function isFlashRequest()
  {
    $header = strtolower($this->getHeader('USER_AGENT'));
    return (strstr($header, ' flash')) ? true : false;
  }
  
  /**
   * Is https secure request
   *
   * @return boolean
   */
  public function isSecure()
  {
    return ($this->getScheme() === self::SCHEME_HTTPS);
  }
  
  /**
   * Retrieve the controller name
   *
   * @return string
   */
  public function getControllerName()
  {
      if (null === $this->controller) {
          $this->controller = $this->getParam($this->getControllerKey());
      }

      return $this->controller;
  }

  /**
   * Set the controller name to use
   *
   * @param string $value
   * @return Zend_Controller_Request_Abstract
   */
  public function setControllerName($value)
  {
      $this->controller = $value;
      return $this;
  }

  /**
   * Retrieve the action name
   *
   * @return string
   */
  public function getActionName()
  {
      if (null === $this->action) {
          $this->action = $this->getParam($this->getActionKey());
      }

      return $this->action;
  }

  /**
   * Set the action name
   *
   * @param string $value
   * @return Zend_Controller_Request_Abstract
   */
  public function setActionName($value)
  {
      $this->action = $value;
      if (null === $value) {
          $this->setParam($this->getActionKey(), $value);
      }
      return $this;
  }

  /**
   * Retrieve the controller key
   *
   * @return string
   */
  public function getControllerKey()
  {
      return $this->controllerKey;
  }

  /**
   * Set the controller key
   *
   * @param string $key
   * @return Zend_Controller_Request_Abstract
   */
  public function setControllerKey($key)
  {
      $this->controllerKey = (string) $key;
      return $this;
  }

  /**
   * Retrieve the action key
   *
   * @return string
   */
  public function getActionKey()
  {
      return $this->actionKey;
  }

  /**
   * Set the action key
   *
   * @param string $key
   * @return Zend_Controller_Request_Abstract
   */
  public function setActionKey($key)
  {
      $this->actionKey = (string) $key;
      return $this;
  }

  /**
   * Retrieve only user params (i.e, any param specific to the object and not the environment)
   *
   * @return array
   */
  public function getUserParams()
  {
      return $this->params;
  }

  /**
   * Retrieve a single user param (i.e, a param specific to the object and not the environment)
   *
   * @param string $key
   * @param string $default Default value to use if key not found
   * @return mixed
   */
  public function getUserParam($key, $default = null)
  {
      if (isset($this->params[$key])) {
          return $this->params[$key];
      }
      return $default;
  }

  /**
   * Unset all user parameters
   *
   * @return Zend_Controller_Request_Abstract
   */
  public function clearParams()
  {
      $this->params = array();
      return $this;
  }

  /**
   * Set flag indicating whether or not request has been dispatched
   *
   * @param boolean $flag
   * @return Zend_Controller_Request_Abstract
   */
  public function setDispatched($flag = true)
  {
      $this->dispatched = $flag ? true : false;
      return $this;
  }

  /**
   * Determine if the request has been dispatched
   *
   * @return boolean
   */
  public function isDispatched()
  {
      return $this->dispatched;
  }
  
}
